#! /usr/bin/env python
#
# Copyright (C) 2011-2013 Christian T. Steigies <steigies@physik.uni-kiel.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""almost_equal: compare two numbers"""

__author__ = "Christian T. Steigies <steigies@physik.uni-kiel.de>"
__license__ = "GPL License"

## --------------------------------------------------------------------------

def almost_equal(num1, num2, places):
    """test if numbers num1 and num2 are equal
       up to places digits after the comma."""

    if (num1 == "NULL") and (num2 == "NULL"):
        return True

    if (num1 == "NULL") or (num2 == "NULL"):
        return False

    if (num1 == None) and (num2 == None):
        return True

    if (num1 == None) or (num2 == None):
        return False

    return (round(float(num1) - float(num2), places) == 0.)


## --------------------------------------------------------------------------
import unittest

class NumberTestCase(unittest.TestCase):
    """testcases with numbers"""
    def test_numbers(self):
        """integers and floats"""
        test_cases = [
                      ((1, 1, 2), True),
                      ((1, 1, 1), True),
                      ((1, 1, 0), True),
                      ((1, 1., 2), True),
                      ((1, 1., 1), True),
                      ((1, 1., 0), True),
                      ((1, 1.001, 2), True),
                      ((1, 1.01, 2), False),
                      ((1, 1.1, 2), False),
                      ((0, 0, 2), True),
                      ((0, 4, -1), True),
                      ((0, 42, -2), True),
                     ]

        for arg, expected in test_cases:
            (num1, num2, places) = arg
            output = almost_equal(num1, num2, places)
            print num1, num2, places, ":", output
            
            self.assertEqual(output, expected)


class NoneTestCase(unittest.TestCase):
    """testcases with None"""
    def test_none(self):
        """None"""
        test_cases = [
                      ((None, None, 2), True),
                      ((None, None, 1), True),
                      ((None, None, 0), True),
                      ((None, 1, 2), False),
                      ((1, None, 2), False),
                      ((None, 0, 2), False),
                      ((0, None, 2), False),
                     ]

        for arg, expected in test_cases:
            (num1, num2, places) = arg
            output = almost_equal(num1, num2, places)
            print num1, num2, places, ":", output
            
            self.assertEqual(output, expected)


class StringTestCase(unittest.TestCase):
    """testcases with strings"""
    def test_none(self):
        """strings vs None, int, and float"""
        test_cases = [
                      (("", None, 2)),
                      (("str", 1, 1)),
                      (("string", 1., 0)),
                     ]

        for arg in test_cases:
            (num1, num2, places) = arg
            print num1, num2, places
            self.assertRaises(ValueError, almost_equal, num1, num2, places)


if __name__ == '__main__':
    unittest.main()
